package com.example.demo.config;

import com.example.demo.utils.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.Objects;

/**
 * @author pinp
 */
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {

    // 可参考：https://juejin.cn/post/6844904003684302861

    @ExceptionHandler(value = {BindException.class})
    public Result handlerBindException(BindException ex, HttpServletRequest req) {
        log.error("BindException ----- Request URI: {}", req.getRequestURI());
        ex.printStackTrace();
        String nullMsg = null;
        String invalidMsg = null;
        try {
            // 拿到@NotNull,@NotBlank和 @NotEmpty等注解上的message值
            nullMsg = Objects.requireNonNull(ex.getBindingResult().getFieldError()).getDefaultMessage();
        } catch (Exception ignored) {
            // pass
        }
        // 参数类型不匹配检验
        StringBuilder msgBuilder = new StringBuilder();
        List<FieldError> fieldErrors = ex.getFieldErrors();
        fieldErrors.forEach((oe) ->
                msgBuilder.append("参数:[").append(oe.getObjectName())
                        .append(".").append(oe.getField())
                        .append("]的传入值:[").append(oe.getRejectedValue()).append("]与预期的字段类型不匹配.")
        );
        invalidMsg = msgBuilder.toString();

        return Result.error(nullMsg != null ? nullMsg : invalidMsg);
    }

    @ExceptionHandler(value = {MethodArgumentNotValidException.class})
    public Result handlerMethodArgumentNotValidException(MethodArgumentNotValidException ex, HttpServletRequest req) {
        log.error("MethodArgumentNotValidException ----- Request URI: {}", req.getRequestURI());
        ex.printStackTrace();
        String msg = Objects.requireNonNull(ex.getBindingResult().getFieldError()).getDefaultMessage();
        msg = "MethodArgumentNotValidException: " + msg;
        return Result.error(msg);
    }

    @ExceptionHandler
    public Result handlerExceptions(Exception ex, HttpServletRequest req) {
        // 打印堆栈，以供调试
        log.error("GlobalException ----- Request URI: {}", req.getRequestURI());
        ex.printStackTrace();
        return Result.error(ex.getMessage());
    }
}
